unit uMain;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms3D, FMX.Forms, FMX.Graphics, FMX.Dialogs
  , Winapi.DXGI
  ;

type
  TForm1 = class(TForm3D)
    procedure Form3DCreate(Sender: TObject);
  private
    { Private declarations }
    FFailureHandled: Boolean;
    procedure OnAsphyreCreate(Sender: TObject; Param: Pointer; var Handled: Boolean);
    procedure OnAsphyreDestroy(Sender: TObject; Param: Pointer; var Handled: Boolean);
    procedure OnDeviceInit(Sender: TObject; Param: Pointer; var Handled: Boolean);
    procedure OnDeviceCreate(Sender: TObject; Param: Pointer; var Handled: Boolean);
    procedure OnTimerReset(Sender: TObject; Param: Pointer; var Handled: Boolean);
    procedure TimerEvent(Sender: TObject);
    procedure ProcessEvent(Sender: TObject);
    procedure RenderEvent(Sender: TObject);
    procedure HandleConnectFailure;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses
  AsphyreDevice, AsphyreCanvas, AsphyreDX10Provider, AsphyreFactory
  , AsphyreEvents, AsphyreTimer, AsphyreWindowsConnector;

var
  G_AsphyreDevice: TAsphyreDevice;
  G_AsphyreCanvas: TAsphyreCanvas;

{$R *.fmx}

procedure TForm1.Form3DCreate(Sender: TObject);
begin
  // Specify that DirectX 9 provider is to be used
  G_Factory.UseProvider(cProviderIDOfDirectX10);

  // This event is called when Asphyre components should be created
  G_EventAsphyreCreate.Subscribe(ClassName, OnAsphyreCreate);

  // This event is called when Asphyre components are to be freed
  G_EventAsphyreDestroy.Subscribe(ClassName, OnAsphyreDestroy);

  // This event is callled before creating Asphyre device to initialize its parameters
  G_EventDeviceInit.Subscribe(ClassName, OnDeviceInit);

  // This event is callled upon Asphyre device creation
  G_EventDeviceCreate.Subscribe(ClassName, OnDeviceCreate);

  // This event is called when creating device and loading data to let the application reset the timer so it does not stall
  G_EventTimerReset.Subscribe(ClassName, OnTimerReset);

  // Initialize and prepare the timer.
  G_Timer.OnTimer := TimerEvent;
  G_Timer.OnProcess := ProcessEvent;
  G_Timer.Enabled := True;

  // This variable tells that a connection failure to Asphyre device has been already handled
  FFailureHandled := False;
end;

procedure TForm1.HandleConnectFailure;
begin

end;

procedure TForm1.OnAsphyreCreate(Sender: TObject; Param: Pointer;
  var Handled: Boolean);
begin
  // Create all Asphyre components
  G_AsphyreDevice := G_Factory.CreateDevice;
  G_AsphyreCanvas := G_Factory.CreateCanvas;
end;

procedure TForm1.OnAsphyreDestroy(Sender: TObject; Param: Pointer;
  var Handled: Boolean);
begin
  G_Timer.Enabled:= False;

  FreeAndNil(G_AsphyreCanvas);
  FreeAndNil(G_AsphyreDevice);
end;

procedure TForm1.OnDeviceCreate(Sender: TObject; Param: Pointer;
  var Handled: Boolean);
begin
  PBoolean(Param)^ := True;
end;

procedure TForm1.OnDeviceInit(Sender: TObject; Param: Pointer;
  var Handled: Boolean);
var
  DisplaySize: TPoint;
begin
  DisplaySize := Point(ClientWidth, ClientHeight);
  G_AsphyreDevice.SwapChains.Add(NativeUInt(Handle), DisplaySize);
end;

procedure TForm1.OnTimerReset(Sender: TObject; Param: Pointer;
  var Handled: Boolean);
begin
  G_Timer.Reset;
end;

procedure TForm1.ProcessEvent(Sender: TObject);
begin
  //
end;

procedure TForm1.RenderEvent(Sender: TObject);
begin
  G_AsphyreCanvas.DrawLine(10, 10, 100, 200, $FFFFFF00);
end;

procedure TForm1.TimerEvent(Sender: TObject);
begin
  // Try to connect Asphyre to the application
  if not G_WindowsConnector.Initialize then
    Exit;

  // In case the device could not be initialized properly (in the frame before
  // this one), show error message and close the form
  if Assigned(G_AsphyreDevice) and G_AsphyreDevice.IsAtFault then
  begin
    if not FFailureHandled then
      HandleConnectFailure;
    FFailureHandled := True;
    Exit;
  end;

  // Initialize Asphyre device, if needed. If this initialization fails, the
  // failure will be handled in the next OnTimer event
  if (not Assigned(G_AsphyreDevice)) or (not G_AsphyreDevice.Connect) then
    Exit;

  // Render the scene
  G_AsphyreDevice.Render(RenderEvent, $000050);

  // Execute constant time processing.
  G_Timer.Process;
end;

end.
